package com.xxl.job.executor.service.jobhandler;

import com.google.common.util.concurrent.*;
import com.ruoyi.bizsys.domain.CreditAccount;
import com.ruoyi.bizsys.service.ICreditAccountService;
import com.ruoyi.business.service.IBRepaymentService;
import com.ruoyi.business.service.IBatchDateJobService;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.system.service.ISysConfigService;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import com.xxl.job.executor.service.thread.CardBatchSplitDebitThread;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

@Component
public class CardBatchSplitDebitJob {

    @Autowired
    IBatchDateJobService batchDateJobService;

    @Autowired
    IBRepaymentService bRepaymentService;

    @Autowired
    ICreditAccountService creditAccountService;

    @Autowired
    RedisCache redisCache;

    @Autowired
    ISysConfigService sysConfigService;

    @Autowired
    RedisTemplate redisTemplate;

    @XxlJob("cardBatchSplitDebitJobHandler")
    public void execute() {
        XxlJobHelper.log("银行卡批量代扣 Start >>>>>>>>>>");

        Integer type = Integer.parseInt(XxlJobHelper.getJobParam());
        saveRedis(type);

        //当天日期
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        //将时分秒置0
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        //开始跑批
        Date nowDate = calendar.getTime();

        //查询批量代扣涉及的用户数
        CreditAccount creditAccount = new CreditAccount();
        creditAccount.setState("1");
        creditAccount.setOnLoan("1");
        List<CreditAccount> accountList = creditAccountService.selectCreditAccountList(creditAccount);
        int accountCount = accountList.size();
        if (accountCount > 0) {
            String redisName = "CardBatchSplitDebit:" + DateUtils.dateTime(nowDate);

            int threadStep = 20;//每个线程执行的客户数
            //需要multiple个线程来执行
            int threadCount = accountCount / threadStep;
            if (threadCount * threadStep != accountCount) {
                threadCount++;
            }
            //线程计数器
            final CountDownLatch countDownLatch = new CountDownLatch(threadCount);
            //线程池大小
            int poolSize = 5;

            ExecutorService executorService = Executors.newFixedThreadPool(poolSize);
            ListeningExecutorService listeningExecutorService = MoreExecutors.listeningDecorator(executorService);

            int threadAccountCount = 0;
            while (threadAccountCount < accountCount) {
                //分页取数startNum
                int startLimit = threadAccountCount;

                threadAccountCount += threadStep;

                if (threadAccountCount > accountCount) {
                    threadAccountCount = accountCount;
                }

                String redisNameSplit = redisName + ":" + startLimit + "-" + threadAccountCount;
                List<CreditAccount> accountSplitList = accountList.subList(startLimit, threadAccountCount);
                redisCache.setCacheList(redisNameSplit, accountSplitList);
                redisCache.expire(redisNameSplit, 23, TimeUnit.HOURS);

                CardBatchSplitDebitThread thread = new CardBatchSplitDebitThread("[CardBatchSplitDebit-" + startLimit + "]", nowDate, redisNameSplit, bRepaymentService, redisCache, type);
                ListenableFuture listenableFuture = listeningExecutorService.submit(thread);

                Futures.addCallback(listenableFuture, new FutureCallback<String>() {
                    @Override
                    public void onSuccess(String result) {
                        countDownLatch.countDown();
                        XxlJobHelper.log("[" + this.getClass().getName() + "]线程处理结果：" + result);
                    }

                    @Override
                    public void onFailure(Throwable throwable) {
                        countDownLatch.countDown();
                        XxlJobHelper.log("[" + this.getClass().getName() + "]线程处理出错：");
                        XxlJobHelper.log(throwable);
                    }
                });
            }

            try {
                countDownLatch.await(3 * 60, TimeUnit.MINUTES);//超过3个小时放弃
            } catch (InterruptedException e) {
                XxlJobHelper.handleSuccess("当日批量代扣执行失败，为正常结束");
            }
        } else {
            XxlJobHelper.log("银行卡批量代扣任务没有记录需要执行");
        }
        clearRedis(type);
        XxlJobHelper.log("银行卡批量代扣 End >>>>>>>>>>");
    }

    @XxlJob("cardBatchSplitDebitByCustNoJobHandler")
    public void cardBatchDebitByCustNo() {
        XxlJobHelper.log("银行卡批量代扣-单个批扣任务 Start >>>>>>>>>>");

        String custNo = XxlJobHelper.getJobParam();
        saveRedis(1);

        CreditAccount creditAccount = new CreditAccount();
        creditAccount.setState("1");
        creditAccount.setOnLoan("1");
        creditAccount.setCustNo(custNo);
        List<CreditAccount> accountList = creditAccountService.selectCreditAccountList(creditAccount);

        if (accountList.size() > 0) {
            bRepaymentService.doBatchRepaymentByAccount(accountList.get(0), 1);
        }
        clearRedis(1);

        XxlJobHelper.log("批量代扣-单个批扣任务 End >>>>>>>>>>");
    }

    public void saveRedis(int type) {
        String minDdaysKey;
        String maxDaysKey;
        String subtractDaysKey;
        String surplusDaysKey;
        if (type == 1) {
            minDdaysKey = "withhold_am_min_days";
            maxDaysKey = "withhold_am_max_days";
            subtractDaysKey = "withhold_am_subtract_days";
            surplusDaysKey = "withhold_am_surplus_days";
        } else if (type == 2) {
            minDdaysKey = "withhold_pm_min_days";
            maxDaysKey = "withhold_pm_max_days";
            subtractDaysKey = "withhold_pm_subtract_days";
            surplusDaysKey = "withhold_pm_surplus_days";
        } else {
            minDdaysKey = "withhold_all_min_days";
            maxDaysKey = "withhold_all_max_days";
            subtractDaysKey = "withhold_all_subtract_days";
            surplusDaysKey = "withhold_all_surplus_days";
        }

        String minDdaysStr = sysConfigService.selectConfigByKey(minDdaysKey);
        Integer minDdays = minDdaysStr == null ? null : Integer.parseInt(minDdaysStr);
        redisCache.setCacheObject("cardBatchSplitDebit:" + type + ":minDdays", minDdays);
        String maxDaysStr = sysConfigService.selectConfigByKey(maxDaysKey);
        Integer maxDays = maxDaysStr == null ? null : Integer.parseInt(maxDaysStr);
        redisCache.setCacheObject("cardBatchSplitDebit:" + type + ":maxDays", maxDays);
        String subtractDaysStr = sysConfigService.selectConfigByKey(subtractDaysKey);
        Integer subtractDays = subtractDaysStr == null ? null : Integer.parseInt(subtractDaysStr);
        redisCache.setCacheObject("cardBatchSplitDebit:" + type + ":subtractDays", subtractDays);
        String surplusDaysStr = sysConfigService.selectConfigByKey(surplusDaysKey);
        Integer surplusDays = surplusDaysStr == null ? null : Integer.parseInt(surplusDaysStr);
        redisCache.setCacheObject("cardBatchSplitDebit:" + type + ":surplusDays", surplusDays);
    }

    public void clearRedis(int type) {
        redisTemplate.delete(redisTemplate.keys("cardBatchSplitDebit:" + type + "*"));
    }

}
